Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(synthetics): node playwright 1.0 and python selenium 4.1 runtime #32245

Open
wants to merge 38 commits into
base: main
Choose a base branch
from

Conversation

badmintoncryer
Copy link
Contributor

Issue # (if applicable)

None

Reason for this change

AWS Synthetics begins supporting the NodeJS Playwright runtime.

https://aws.amazon.com/about-aws/whats-new/2024/11/amazon-cloudwatch-synthetics-playwright-runtime-canaries-nodejs/

And Python Selenium runtime v4.1 is also released.

https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Library_python_selenium.html#CloudWatch_Synthetics_runtimeversion-syn-python-selenium-4.1

Description of changes

Add two runtimes to Runtime class

  • SYNTHETICS_PYTHON_SELENIUM_4_1
  • SYNTHETICS_NODEJS_PLAYWRIGHT_1_0

Description of how you validated changes

Execute describe-runtime AWS CLI.

aws synthetics describe-runtime-versions --region us-east-1 | grep VersionName
            "VersionName": "syn-python-selenium-4.1",
            ...,
            "VersionName": "syn-nodejs-playwright-1.0",
            ...

Checklist


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

@github-actions github-actions bot added the p2 label Nov 22, 2024
@aws-cdk-automation aws-cdk-automation requested a review from a team November 22, 2024 04:09
@github-actions github-actions bot added the distinguished-contributor [Pilot] contributed 50+ PRs to the CDK label Nov 22, 2024
Copy link

codecov bot commented Nov 22, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 81.38%. Comparing base (78fba23) to head (33c557d).
Report is 6 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #32245      +/-   ##
==========================================
- Coverage   81.52%   81.38%   -0.15%     
==========================================
  Files         222      222              
  Lines       13717    13695      -22     
  Branches     2417     2412       -5     
==========================================
- Hits        11183    11145      -38     
- Misses       2254     2271      +17     
+ Partials      280      279       -1     
Flag Coverage Δ
suite.unit 81.38% <ø> (-0.15%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
packages/aws-cdk 80.69% <ø> (-0.29%) ⬇️
packages/aws-cdk-lib/core 82.09% <ø> (ø)

@aws-cdk-automation aws-cdk-automation added the pr/needs-community-review This PR needs a review from a Trusted Community Member or Core Team Member. label Nov 22, 2024
@aws-cdk-automation aws-cdk-automation added pr/needs-maintainer-review This PR needs a review from a Core Team Member and removed pr/needs-community-review This PR needs a review from a Trusted Community Member or Core Team Member. labels Nov 22, 2024
@badmintoncryer badmintoncryer changed the title chore(synthetics): node playwright and python selenium runtime chore(synthetics): node playwright 1.0 and python selenium 4.1 runtime Nov 22, 2024
Copy link
Contributor

@gracelu0 gracelu0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the PR! Could we name this PR with feat instead of chore and add to this integ test: https://github.com/aws/aws-cdk/blob/main/packages/%40aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary.ts?

@aws-cdk-automation aws-cdk-automation removed the pr/needs-maintainer-review This PR needs a review from a Core Team Member label Nov 25, 2024
@badmintoncryer badmintoncryer changed the title chore(synthetics): node playwright 1.0 and python selenium 4.1 runtime feat(synthetics): node playwright 1.0 and python selenium 4.1 runtime Nov 28, 2024
Copy link
Collaborator

@aws-cdk-automation aws-cdk-automation left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pull request linter has failed. See the aws-cdk-automation comment below for failure reasons. If you believe this pull request should receive an exemption, please comment and provide a justification.

A comment requesting an exemption should contain the text Exemption Request. Additionally, if clarification is needed add Clarification Request to a comment.

@aws-cdk-automation aws-cdk-automation dismissed their stale review November 29, 2024 00:39

✅ Updated pull request passes all PRLinter validations. Dismissing previous PRLinter review.

@mergify mergify bot dismissed gracelu0’s stale review November 29, 2024 13:14

Pull request has been modified.

@badmintoncryer
Copy link
Contributor Author

@gracelu0 Thank you for your review! I have some problems.

Currently, the code cannot deploy the PlayWright runtime, so I would like to modify the validateCanaryAsset() function to accept Runtime instead of RuntimeFamily as its argument.

-  private validateCanaryAsset(scope: Construct, handler: string, family: RuntimeFamily) {
+  private validateCanaryAsset(scope: Construct, handler: string, runtime: Runtime) {

To align with this change, the bind() function's arguments also need to be updated.

- public bind(scope: Construct, handler: string, family: RuntimeFamily): CodeConfig {
+ public bind(scope: Construct, handler: string, runtime: Runtime): CodeConfig {

However, this would introduce a breaking change to a public function, causing the CI to fail.

API elements with incompatible changes:
err  - METHOD aws-cdk-lib.aws_synthetics.AssetCode.bind: argument family, takes aws-cdk-lib.aws_synthetics.Runtime (formerly aws-cdk-lib.aws_synthetics.RuntimeFamily): aws-cdk-lib.aws_synthetics.RuntimeFamily is an enum different from aws-cdk-lib.aws_synthetics.Runtime [incompatible-argument:aws-cdk-lib.aws_synthetics.AssetCode.bind]
err  - METHOD aws-cdk-lib.aws_synthetics.Code.bind: argument family, takes aws-cdk-lib.aws_synthetics.Runtime (formerly aws-cdk-lib.aws_synthetics.RuntimeFamily): aws-cdk-lib.aws_synthetics.RuntimeFamily is an enum different from aws-cdk-lib.aws_synthetics.Runtime [incompatible-argument:aws-cdk-lib.aws_synthetics.Code.bind]
err  - METHOD aws-cdk-lib.aws_synthetics.InlineCode.bind: argument _family, takes aws-cdk-lib.aws_synthetics.Runtime (formerly aws-cdk-lib.aws_synthetics.RuntimeFamily): aws-cdk-lib.aws_synthetics.RuntimeFamily is an enum different from aws-cdk-lib.aws_synthetics.Runtime [incompatible-argument:aws-cdk-lib.aws_synthetics.InlineCode.bind]
err  - METHOD aws-cdk-lib.aws_synthetics.S3Code.bind: argument _family, takes aws-cdk-lib.aws_synthetics.Runtime (formerly aws-cdk-lib.aws_synthetics.RuntimeFamily): aws-cdk-lib.aws_synthetics.RuntimeFamily is an enum different from aws-cdk-lib.aws_synthetics.Runtime [incompatible-argument:aws-cdk-lib.aws_synthetics.S3Code.bind]
Checking region info facts... OK.
Some packages seem to have undergone breaking API changes. Please avoid.

Could you provide some advice on how to approach this modification?

Copy link
Contributor

@nmussy nmussy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't have a chance to go over everything, but from what little testing I ran before being made aware of my duplicate implementation:

  • activeTracing is not (yet?) supported for Playwright. Despite being allowed as a Node.js Runtime by the CDK, CloudFormation will throw on deployment

    if (props.activeTracing && !cdk.Token.isUnresolved(props.runtime.family) && props.runtime.family !== RuntimeFamily.NODEJS) {
    throw new Error('You can only enable active tracing for canaries that use canary runtime version `syn-nodejs-2.0` or later.');
    }

  • I'm not sure about artifactS3EncryptionMode, but the CDK allows the use of the property as well, so it would at least require updating the error message and adding integration coverage

    if (!isNodeRuntime && props.artifactS3EncryptionMode) {
    throw new Error(`Artifact encryption is only supported for canaries that use Synthetics runtime version \`syn-nodejs-puppeteer-3.3\` or later, got \`${props.runtime.name}\`.`);
    }

Comment on lines 102 to 103
const puppeteer80 = createCanaryByRuntimes(Runtime.SYNTHETICS_NODEJS_PUPPETEER_8_0);
const playwright10 = createCanaryByRuntimes(Runtime.SYNTHETICS_NODEJS_PLAYWRIGHT_1_0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add tests for SYNTHETICS_NODEJS_PUPPETEER_9_0 and SYNTHETICS_NODEJS_PUPPETEER_9_1? They weren't covered when they were added

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added!

Comment on lines 147 to 148
const hasValidExtension = playwrightValidExtensions.some(ext => fs.existsSync(path.join(assetPath, `${filename}${ext}`)));
if (runtime.family === RuntimeFamily.NODEJS && runtime.name.includes('puppeteer') && !fs.existsSync(path.join(assetPath, 'nodejs', 'node_modules', nodeFilename))) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Playwright canaries should support multiple directories (e.g. a/b/c/entrypoint.mjs), see docs:

Optionally, you can also store your entry point file in a folder structure of your choice. However, be sure that the folder path is specified in your handler name.

I think the validation would handle it fine, but could you add a unit test and an integ to make sure we support it correctly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your information. I don't know that.
I've created both integ and unit test for multiple directories.

@aws-cdk-automation
Copy link
Collaborator

This PR cannot be merged because it has conflicts. Please resolve them. The PR will be considered stale and closed if it remains in an unmergeable state.

@aws-cdk-automation
Copy link
Collaborator

This PR has been in the BUILD FAILING state for 3 weeks, and looks abandoned. To keep this PR from being closed, please continue work on it. If not, it will automatically be closed in a week.

@badmintoncryer
Copy link
Contributor Author

@go-to-k @nmussy @gracelu0 Thank you, everyone. As suggested, I will try modifying it by adding optional arguments.
Wishing you all a Happy New Year!

packages/aws-cdk-lib/aws-synthetics/lib/code.ts Outdated Show resolved Hide resolved
Comment on lines 145 to 171
// Validation can be performed using both `RuntimeFamily` and `runtimeName` arguments,
// but for backward compatibility of `Code.bind()`, it is also designed to accept only `RuntimeFamily`.
if (runtimeName && !Token.isUnresolved(runtimeName)) {
const filename = handler.split('.')[0];
const nodeFilename = `${filename}.js`;
const pythonFilename = `${filename}.py`;
const playwrightValidExtensions = ['.cjs', '.mjs', '.js'];
const hasValidExtension = playwrightValidExtensions.some(ext => fs.existsSync(path.join(assetPath, `${filename}${ext}`)));
if (family === RuntimeFamily.NODEJS && runtimeName.includes('puppeteer') && !fs.existsSync(path.join(assetPath, 'nodejs', 'node_modules', nodeFilename))) {
throw new Error(`The canary resource requires that the handler is present at "nodejs/node_modules/${nodeFilename}" but not found at ${this.assetPath} (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_WritingCanary_Nodejs.html)`);
}
if (family === RuntimeFamily.NODEJS && runtimeName.includes('playwright') && !hasValidExtension) {
throw new Error(`The canary resource requires that the handler is present at one of the following extensions: ${playwrightValidExtensions.join(', ')} but not found at ${this.assetPath}`);
}
if (family === RuntimeFamily.PYTHON && !fs.existsSync(path.join(assetPath, 'python', pythonFilename))) {
throw new Error(`The canary resource requires that the handler is present at "python/${pythonFilename}" but not found at ${this.assetPath} (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_WritingCanary_Python.html)`);
}
} else {
const filename = handler.split('.')[0];
const nodeFilename = `${filename}.js`;
const pythonFilename = `${filename}.py`;
if (family === RuntimeFamily.NODEJS && !fs.existsSync(path.join(assetPath, 'nodejs', 'node_modules', nodeFilename))) {
throw new Error(`The canary resource requires that the handler is present at "nodejs/node_modules/${nodeFilename}" but not found at ${this.assetPath} (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_WritingCanary_Nodejs.html)`);
}
if (family === RuntimeFamily.PYTHON && !fs.existsSync(path.join(assetPath, 'python', pythonFilename))) {
throw new Error(`The canary resource requires that the handler is present at "python/${pythonFilename}" but not found at ${this.assetPath} (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_WritingCanary_Python.html)`);
}
Copy link
Contributor

@go-to-k go-to-k Jan 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to simplify it a bit more to make it more readable.

One example:

Suggested change
// Validation can be performed using both `RuntimeFamily` and `runtimeName` arguments,
// but for backward compatibility of `Code.bind()`, it is also designed to accept only `RuntimeFamily`.
if (runtimeName && !Token.isUnresolved(runtimeName)) {
const filename = handler.split('.')[0];
const nodeFilename = `${filename}.js`;
const pythonFilename = `${filename}.py`;
const playwrightValidExtensions = ['.cjs', '.mjs', '.js'];
const hasValidExtension = playwrightValidExtensions.some(ext => fs.existsSync(path.join(assetPath, `${filename}${ext}`)));
if (family === RuntimeFamily.NODEJS && runtimeName.includes('puppeteer') && !fs.existsSync(path.join(assetPath, 'nodejs', 'node_modules', nodeFilename))) {
throw new Error(`The canary resource requires that the handler is present at "nodejs/node_modules/${nodeFilename}" but not found at ${this.assetPath} (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_WritingCanary_Nodejs.html)`);
}
if (family === RuntimeFamily.NODEJS && runtimeName.includes('playwright') && !hasValidExtension) {
throw new Error(`The canary resource requires that the handler is present at one of the following extensions: ${playwrightValidExtensions.join(', ')} but not found at ${this.assetPath}`);
}
if (family === RuntimeFamily.PYTHON && !fs.existsSync(path.join(assetPath, 'python', pythonFilename))) {
throw new Error(`The canary resource requires that the handler is present at "python/${pythonFilename}" but not found at ${this.assetPath} (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_WritingCanary_Python.html)`);
}
} else {
const filename = handler.split('.')[0];
const nodeFilename = `${filename}.js`;
const pythonFilename = `${filename}.py`;
if (family === RuntimeFamily.NODEJS && !fs.existsSync(path.join(assetPath, 'nodejs', 'node_modules', nodeFilename))) {
throw new Error(`The canary resource requires that the handler is present at "nodejs/node_modules/${nodeFilename}" but not found at ${this.assetPath} (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_WritingCanary_Nodejs.html)`);
}
if (family === RuntimeFamily.PYTHON && !fs.existsSync(path.join(assetPath, 'python', pythonFilename))) {
throw new Error(`The canary resource requires that the handler is present at "python/${pythonFilename}" but not found at ${this.assetPath} (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_WritingCanary_Python.html)`);
}
const filename = handler.split('.')[0];
const nodeFilename = `${filename}.js`;
const pythonFilename = `${filename}.py`;
// Validation can be performed using both `RuntimeFamily` and `runtimeName` arguments,
// but for backward compatibility of `Code.bind()`, it is also designed to accept only `RuntimeFamily`.
if (runtimeName && !Token.isUnresolved(runtimeName)) {
const playwrightValidExtensions = ['.cjs', '.mjs', '.js'];
const hasValidExtension = playwrightValidExtensions.some(ext => fs.existsSync(path.join(assetPath, `${filename}${ext}`)));
if (family === RuntimeFamily.NODEJS && runtimeName.includes('puppeteer') && !fs.existsSync(path.join(assetPath, 'nodejs', 'node_modules', nodeFilename))) {
throw new Error(`The canary resource requires that the handler is present at "nodejs/node_modules/${nodeFilename}" but not found at ${this.assetPath} (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_WritingCanary_Nodejs.html)`);
}
if (family === RuntimeFamily.NODEJS && runtimeName.includes('playwright') && !hasValidExtension) {
throw new Error(`The canary resource requires that the handler is present at one of the following extensions: ${playwrightValidExtensions.join(', ')} but not found at ${this.assetPath}`);
}
} else if (family === RuntimeFamily.NODEJS && !fs.existsSync(path.join(assetPath, 'nodejs', 'node_modules', nodeFilename))) {
throw new Error(`The canary resource requires that the handler is present at "nodejs/node_modules/${nodeFilename}" but not found at ${this.assetPath} (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_WritingCanary_Nodejs.html)`);
}
if (family === RuntimeFamily.PYTHON && !fs.existsSync(path.join(assetPath, 'python', pythonFilename))) {
throw new Error(`The canary resource requires that the handler is present at "python/${pythonFilename}" but not found at ${this.assetPath} (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_WritingCanary_Python.html)`);
}

However, I am not sure if the following validation is good when runtimeName is a token, i.e., when there is a possibility that it may be a playwright instead of a puppeteer.

      // If runtimeName is a Token and the following is true:
      } else if (family === RuntimeFamily.NODEJS && !fs.existsSync(path.join(assetPath, 'nodejs', 'node_modules', nodeFilename))) {
        throw new Error(`The canary resource requires that the handler is present at "nodejs/node_modules/${nodeFilename}" but not found at ${this.assetPath} (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Canaries_WritingCanary_Nodejs.html)`);
      }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your great suggestion.

However, I am not sure if the following validation is good when runtimeName is a token, i.e., when there is a possibility that it may be a playwright instead of a puppeteer.

I have removed this validation because it would be an issue if the token was "playwright" and caused an error.

Copy link
Contributor

@go-to-k go-to-k left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@liuxiax
Copy link

liuxiax commented Jan 6, 2025

@badmintoncryer Hi, would you mind taking a look at the failed check and update the branch? Thanks :)

@badmintoncryer
Copy link
Contributor Author

@liuxiax Hello, CodeQL job has failed but this is caused by auto generated snapshots code. I think this is not a problem.
What do you think?

@gracelu0 gracelu0 self-assigned this Jan 8, 2025
Copy link
Contributor

@gracelu0 gracelu0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @badmintoncryer , thank you for all your effort on this! And thank you to @go-to-k and @nmussy for your thorough review :) Just a few more nit comments and then I'm good to approve.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: for L183 and L184, should be See the Note below for directory structure

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is above😁 Thanks!

if (runtimeName && !Token.isUnresolved(runtimeName)) {
const playwrightValidExtensions = ['.cjs', '.mjs', '.js'];
const hasValidExtension = playwrightValidExtensions.some(ext => fs.existsSync(path.join(assetPath, `${filename}${ext}`)));
if (family === RuntimeFamily.NODEJS && runtimeName.includes('puppeteer') && !fs.existsSync(path.join(assetPath, 'nodejs', 'node_modules', nodeFilename))) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add the comments about the validation checks (e.g. * Requires asset directory to have the structure 'nodejs/node_modules' for puppeteer runtime.) inside the function here to make it a bit easier to follow?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the nice suggestion. I've updated.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Could you repeat the same for the other validation checks (python, playwright)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added!

@badmintoncryer
Copy link
Contributor Author

@gracelu0 Thank you for your review! I've addressed all of your comments.

@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildv2Project1C6BFA3F-wQm2hXv2jqQv
  • Commit ID: 33c557d
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
distinguished-contributor [Pilot] contributed 50+ PRs to the CDK p2 pr/needs-maintainer-review This PR needs a review from a Core Team Member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants